#include <GL/glut.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>

#define PI 3.141592654

typedef struct {
   float x;
   float y;
}Punto;

void inicializa(void);
void dibuja(void);
void tecladoEspecial(int key, int cx, int cy);
void teclado(unsigned char key, int cx, int cy);
void llenaEstrella(float, float);
void traslacion(Punto);
void rotacion(float);
float grados2Radianes(float);

Punto estrella[11];
Punto transformacion[11];

Punto fijo;
float theta;

int main(int argc, char* argv[]) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(640,480);
    glutInitWindowPosition(100, 150);
    glutCreateWindow("Transformaciones");
    inicializa();

    glutDisplayFunc(dibuja);
    glutSpecialFunc(tecladoEspecial);
    glutKeyboardFunc(teclado);


    glutMainLoop();
    return 0;
}

void inicializa() {
	int i;

    glClearColor(0.0, 0.0, 0.0, 1.0);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(-320, 320.0, -240.0, 240.0);

    //Llenamos la estrella
    llenaEstrella(15.0, 40);

    //La primera transformacion es la identidad
    for (i = 0; i < 11; i++) {
    	transformacion[i].x = estrella[i].x;
    	transformacion[i].y = estrella[i].y;
    }

    //Ponemos a fijo en 0
    fijo.x = 0.0;
    fijo.y = 0.0;

    //Ponemos theta en 0
    theta = 0.0;
}

void dibuja(void) {
	int i;
    glClear(GL_COLOR_BUFFER_BIT);

    traslacion(fijo);
    rotacion(grados2Radianes(theta));
    
    //Pintar un punto en el eje de rotacion
    glColor3f(1.0, 0.0, 0.0);
    glPointSize(3.0);
    glBegin(GL_POINTS);
    	glVertex2f(0.0, 0.0);
    glEnd();
    
    //Y una linea para verlo mas claro
    glLineWidth(2.0);
    glColor3f(1.0, 0.0, 0.0);
    glBegin(GL_LINES);
    	glVertex2f(0.0, 0.0);
    	glVertex2f(transformacion[0].x, transformacion[0].y);
    glEnd();

    glColor3f(1.0, 1.0, 1.0);
    glBegin(GL_LINE_LOOP);
    for(i = 1; i <= 10; i++) {
    	glVertex2f(transformacion[i].x, transformacion[i].y);
	}
    glEnd();

    glFlush();
}

void tecladoEspecial (int key, int cx, int cy) {

	switch(key) {
		case GLUT_KEY_RIGHT:
			fijo.x += 5.0;
		break;

		case GLUT_KEY_LEFT:
			fijo.x -= 5.0;
		break;

		case GLUT_KEY_UP:
			fijo.y += 5.0;
		break;

		case GLUT_KEY_DOWN:
			fijo.y -= 5.0;
		break;

		case GLUT_KEY_PAGE_UP:
			theta += 10.0;
		break;

		case GLUT_KEY_PAGE_DOWN:
			theta -= 10.0;
		break;

	}

	glutPostRedisplay();
}

void teclado (unsigned char key, int cx, int cy) {
	switch(key) {

		case 27:
			exit(0);
		break;

		case 'r':
		case 'R':
			theta = 0.0;
			fijo.x = 0.0;
			fijo.y = 0.0;
		break;

	}

	glutPostRedisplay();
}

void llenaEstrella (float minRadi, float maxRadi) {
	float delta = 2.0 * PI / 10.0, x, y, radius, angle;
	int i;

	angle = PI / 2.0;

	//El primer punto para guardar el centro
	estrella[0].x = estrella[0].y = 0.0;
	
	for (i = 1; i <= 10; i++) {
		radius = (i % 2) ? minRadi : maxRadi;
		x = radius * cos(angle);
		y = radius * sin(angle);
		estrella[i].x = x;
		estrella[i].y = y;
		angle += delta;
	}

}

void traslacion (Punto u) {
	int i;
	for (i = 0; i < 11; i++) {
		transformacion[i].x = estrella[i].x + u.x;
		transformacion[i].y = estrella[i].y + u.y;
	}
}

void rotacion (float theta) {
	int i;
	float a = cos(theta), b = sin(theta);
	float aX, aY;

	for (i = 0; i < 11; i++) {
		aX = transformacion[i].x;
		aY = transformacion[i].y;
		transformacion[i].x = aX * a - aY * b;
		transformacion[i].y = aX * b + aY * a;
	}
}

float grados2Radianes(float theta) {
	return theta * PI / 180.0;
}
